#pragma once
//阻塞等待队里的实现
#include <iostream>
#include <queue>
#include<pthread.h>
static int defaultNum=10;

template<class T>//设置成模版类可支持存放其他类型数据
class BlockingQueue
{

    private:
    std::queue<T> blockqueue;//数据交易地点
    int Max_capacity;//代表队列能存放的最大数据个数
    pthread_mutex_t mutex_;//用锁实现互斥关系
    pthread_cond_t cond_p;//用条件变量实现同步关系
    pthread_cond_t cond_c;//消费者到消费者的等待队列、生产者到生产者的等待队列
    private:
    void lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    bool isempty()
    {
        return blockqueue.size()==0;
    }
    public:
    BlockingQueue(int maxcapacity=defaultNum)
    :Max_capacity(maxcapacity)
    {
        //锁和条件变量初始化
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_p,nullptr);
        pthread_cond_init(&cond_c,nullptr);
    }
    void push(const T& data)
    {
        //往队列生产数据
        //如果数据满了，让生产到等待队列里等待
        lock();//访问队列前先上锁
        while(Max_capacity==blockqueue.size())//用while防止伪唤醒
        {
            pthread_cond_wait(&cond_p,&mutex_);//等待并解锁
        }
        blockqueue.push(data);//走到这里说明 1.队列不为满  2.生产者被唤醒且队列不为满
        pthread_cond_signal(&cond_c);//生产一个数据就唤醒一个消费者来消费（同步）
        unlock();//访问结束解锁
    }
    T pop()
    {
        //从队列中消费数据
            lock();//访问前先上锁
            while(isempty())//消费前先判空,while循环防止伪唤醒
            {
                //如果为空到消费者的等待队列里等、
                pthread_cond_wait(&cond_c,&mutex_);
            }
            T out=blockqueue.front();
            blockqueue.pop();
            pthread_cond_signal(&cond_p);//消费一个数据唤醒一次生产者队列
            unlock();
            return out;

    }
    ~BlockingQueue()
    {
        //锁、条件变量销毁
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_c);
        pthread_cond_destroy(&cond_p);
    }
};